package wxchat

import (
	"encoding/json"
	"strconv"
	"time"

	"gitee.com/itsos/wxsdk/common/global"
	"gitee.com/itsos/wxsdk/common/http"
	"gitee.com/itsos/wxsdk/common/storage"
)

type wxChatHttp interface {
	get(url string) []byte
	getKey() string
	setKey(key string)
	setLockKey(lockKey string)
	getLockKey() string
	setExpire(expire int)
	getExpire() int
}

type chatHttp struct {
	key     string
	lockKey string
	expire  int
}

func (c *chatHttp) setExpire(expire int) {
	c.expire = expire
}

func (c *chatHttp) getExpire() int {
	return c.expire
}

func (c *chatHttp) getKey() string {
	return c.key
}

func (c *chatHttp) setKey(key string) {
	c.key = key
}

func (c *chatHttp) setLockKey(lockKey string) {
	c.lockKey = lockKey
}

func (c *chatHttp) getLockKey() string {
	return c.lockKey
}

func (c *chatHttp) get(url string) []byte {
	lockKey := c.getLockKey()
	key := c.getKey()

	var (
		isBool    bool
		err       error
		ttl       time.Duration
		resp      []byte
		respCache string
	)

	// 并发处理
	for {
		if ttl, err = storage.Store().GetExpire(key); ttl.Seconds() > 0 {
			respCache, err = storage.Store().Get(key)
			if err == nil {
				return []byte(respCache)
			}
		}
		if isBool, err = storage.Store().Lock(lockKey, time.Minute); err == nil && isBool {
			if ttl, err = storage.Store().GetExpire(key); err == nil && ttl.Seconds() <= 0 {
				break
			}
		}
		time.Sleep(time.Millisecond * 500)
	}
	defer func(store storage.Storage, key string) {
		err := store.Remove(key)
		if err != nil {
			panic(err)
		}
	}(storage.Store(), lockKey)

	// http request wx service
	resp = http.Get(url)

	var errorDTO = &global.ErrorDTO{}
	if err = json.Unmarshal(resp, errorDTO); err != nil {
		panic(err)
	}
	if errorDTO.ErrCode != 0 {
		panic(strconv.Itoa(errorDTO.ErrCode) + "#" + errorDTO.ErrMsg)
	}
	err = storage.Store().Set(key, string(resp), time.Duration(int(time.Second)*c.getExpire()))
	if err != nil {
		panic(err)
	}
	return resp
}

var _ wxChatHttp = (*chatHttp)(nil)

func newHttp() wxChatHttp {
	return new(chatHttp)
}
